﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using ExpenseTracker.Entity;
using ExpenseTracker.Controller;

namespace ExpenseTracker
{
    public partial class ExpenseForm : BaseForm
    {
        public delegate void ExpenseFormSaved();
        public event ExpenseFormSaved OnExpenseFormSaved;

        private ExpenseTracker.Controller.CategoryController _categoryController;
        private ExpenseTracker.Controller.ExpenseController _expenseController;
        private ExpenseTracker.Entity.Expense _expense;

        public ExpenseForm(ExpenseTracker.Entity.Account account) : base(account)
        {
            _categoryController = new CategoryController(account);
            _expenseController = new ExpenseController(account);
            _expense = new Expense();
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            PopulateCategoryComboBox();
            PopulateForm();
            btnDelete.Enabled = (FormAction == FormAction.Create) ? false : true;
            base.OnLoad(e);
        }

        public ExpenseTracker.Entity.Expense Expense
        {
            get { return _expense; }
            set { _expense = value; }
        }

        protected void PopulateForm()
        {
            if (FormAction == FormAction.Update && Expense.ExpenseID > 0)
            {
                Expense = _expenseController.GetExpense(Expense.ExpenseID);

                for (int i = 0; i < cbCategory.Items.Count; i++)
                {
                    Category category = cbCategory.Items[i] as Category;
                    if (category.CategoryID == Expense.CategoryID)
                    {
                        cbCategory.SelectedItem = cbCategory.Items[i];
                        break;
                    }
                }

                dtpTransactionDate.Value = Expense.TransactionDate;
                txtItem.Text = Expense.Item;
                txtDescription.Text = Expense.Description;
                SetDefaultNumberValue(txtAmount, Expense.Amount);
                SetDefaultNumberValue(txtGST, Expense.GST);
                SetDefaultNumberValue(txtPST, Expense.PST);
                SetDefaultNumberValue(txtTotal, Expense.Total);
                chkIsDisabled.Checked = Expense.IsDisabled;
            }
        }

        protected void PopulateCategoryComboBox()
        {
            cbCategory.Items.Clear();
            List<Category> list = _categoryController.GetCategories(TransactionType.Expense);
            foreach (Category item in list)
            {
                cbCategory.Items.Add(item);
            }
            cbCategory.DisplayMember = "Title";
            cbCategory.ValueMember = "CategoryID";
        }

        protected bool ValidateForm()
        {
            bool valid = true;
            StringBuilder sb = new StringBuilder();

            if (cbCategory.SelectedItem == null)
            {
                sb.Append("- Select category." + Environment.NewLine);
                valid = false;
            }

            if (String.IsNullOrEmpty(txtItem.Text.Trim()))
            {
                sb.Append("- Enter item." + Environment.NewLine);
                valid = false;
            }

            SetDefaultNumberValue(txtAmount, 0.0F);
            SetDefaultNumberValue(txtGST, 0.0F);
            SetDefaultNumberValue(txtPST, 0.0F);
            SetDefaultNumberValue(txtTotal, 0.0F);

            ValidateNumberValue(txtAmount, "- Enter valid amount.", ref sb, ref valid);
            ValidateNumberValue(txtGST, "- Enter valid GST.", ref sb, ref valid);
            ValidateNumberValue(txtPST, "- Enter valid PST.", ref sb, ref valid);
            ValidateNumberValue(txtTotal, "- Enter valid total.", ref sb, ref valid);

            if (!valid)
            {
                MessageBox.Show("Error:" + Environment.NewLine + sb.ToString());
            }

            return valid;
        }

        protected void FormToObject()
        {
            if (FormAction == FormAction.Create)
            {
                Expense = new Expense();
                Expense.TransactionDate = dtpTransactionDate.Value;
                if (cbCategory.SelectedItem != null)
                {
                    Category category = cbCategory.SelectedItem as Category;
                    Expense.CategoryID = category.CategoryID;
                }
                Expense.Item = txtItem.Text.Trim();
                Expense.Description = txtDescription.Text.Trim();
                Expense.Amount = GetNumberValue(txtAmount, 0.0F);
                Expense.GST = GetNumberValue(txtGST, 0.0F);
                Expense.PST = GetNumberValue(txtPST, 0.0F);
                Expense.Total = GetNumberValue(txtTotal, 0.0F);
                Expense.IsDisabled = chkIsDisabled.Checked;
            }
            else if (FormAction == FormAction.Update)
            {
                Expense.TransactionDate = dtpTransactionDate.Value;
                if (cbCategory.SelectedItem != null)
                {
                    Category category = cbCategory.SelectedItem as Category;
                    Expense.CategoryID = category.CategoryID;
                }
                Expense.Item = txtItem.Text.Trim();
                Expense.Description = txtDescription.Text.Trim();
                Expense.Amount = GetNumberValue(txtAmount, 0.0F);
                Expense.GST = GetNumberValue(txtGST, 0.0F);
                Expense.PST = GetNumberValue(txtPST, 0.0F);
                Expense.Total = GetNumberValue(txtTotal, 0.0F);
                Expense.IsDisabled = chkIsDisabled.Checked;
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (ValidateForm())
            {
                FormToObject();
                if (FormAction == FormAction.Create)
                {
                    _expenseController.InsertExpense(Expense);
                }
                else if (FormAction == FormAction.Update)
                {
                    _expenseController.UpdateExpense(Expense);
                }

                if (OnExpenseFormSaved != null)
                {
                    OnExpenseFormSaved();
                }
                this.Close();
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure to delete this expense?", "Delete Expense", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                _expenseController.DeleteExpense(Expense.ExpenseID);
                if (OnExpenseFormSaved != null)
                {
                    OnExpenseFormSaved();
                }
                this.Close();
            }
        }    

        #region Leave event handlers
        private void txtAmount_Leave(object sender, EventArgs e)
        {
            float amount = GetNumberValue(txtAmount, 0.0F);
            float gst = amount * Configuration.Instance.GSTRate;
            float pst = amount * Configuration.Instance.PSTRate;
            float total = amount + gst + pst;
            txtGST.Text = gst.ToString("N2");
            txtPST.Text = pst.ToString("N2");
            txtTotal.Text = total.ToString("N2");
            SetDefaultNumberValue(txtAmount, 0.0F);
        }

        private void txtGST_Leave(object sender, EventArgs e)
        {
            float amount = GetNumberValue(txtAmount, 0.0F);
            float gst = GetNumberValue(txtGST, 0.0F);
            float pst = amount * Configuration.Instance.PSTRate;
            float total = amount + gst + pst;
            txtPST.Text = pst.ToString("N2");
            txtTotal.Text = total.ToString("N2");
            SetDefaultNumberValue(txtGST, 0.0F);
        }

        private void txtPST_Leave(object sender, EventArgs e)
        {
            float amount = GetNumberValue(txtAmount, 0.0F);
            float gst = GetNumberValue(txtGST, 0.0F);
            float pst = GetNumberValue(txtPST, 0.0F);
            float total = amount + gst + pst;
            txtTotal.Text = total.ToString("N2");
            SetDefaultNumberValue(txtPST, 0.0F);
        }

        private void txtTotal_Leave(object sender, EventArgs e)
        {
            SetDefaultNumberValue(txtTotal, 0.0F);
        }
        #endregion

        #region KeyPress event handlers
        private void txtAmount_KeyPress(object sender, KeyPressEventArgs e)
        {
            ValidateNumberValue(sender, e);
            TrySubmitForm(sender, e);
        }

        private void txtGST_KeyPress(object sender, KeyPressEventArgs e)
        {
            ValidateNumberValue(sender, e);
            TrySubmitForm(sender, e);
        }

        private void txtPST_KeyPress(object sender, KeyPressEventArgs e)
        {
            ValidateNumberValue(sender, e);
            TrySubmitForm(sender, e);
        }

        private void txtTotal_KeyPress(object sender, KeyPressEventArgs e)
        {
            ValidateNumberValue(sender, e);
            TrySubmitForm(sender, e);
        }

        private void txtItem_KeyPress(object sender, KeyPressEventArgs e)
        {
            TrySubmitForm(sender, e);
        }
        #endregion

        #region Number utilties
        private void SetDefaultNumberValue(TextBox textbox, float defaultValue)
        {
            if (String.IsNullOrEmpty(textbox.Text.Trim()))
            {
                textbox.Text = defaultValue.ToString("N2");
            }
        }

        private float GetNumberValue(TextBox textbox, float defaultValue)
        {
            float val = defaultValue;
            if (!String.IsNullOrEmpty(textbox.Text.Trim()))
            {
                if (float.TryParse(textbox.Text.Trim(), out val))
                {
                    return val;
                }
            }
            return val;
        }

        private void ValidateNumberValue(object sender, KeyPressEventArgs e)
        {
            Match match = Regex.Match(e.KeyChar.ToString(), @"\d|\.");
            if (!match.Success)
            {
                e.Handled = true;
            }
            else
            {
                TextBox textbox = (TextBox)sender;
                string text = textbox.Text.Trim() + e.KeyChar.ToString();
                if (!String.IsNullOrEmpty(text))
                {
                    float val;
                    if (!float.TryParse(text, out val))
                    {
                        e.Handled = true;
                    }
                }
            }
        }

        private void TrySubmitForm(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == Convert.ToChar(Keys.Enter))
            {
                btnSave_Click(this, null);
            }
        }

        private void ValidateNumberValue(TextBox textbox, string message, ref StringBuilder sb, ref bool valid)
        {
            float val;
            if (!float.TryParse(textbox.Text.Trim(), out val))
            {
                sb.Append(message + Environment.NewLine);
                valid = false;
            }
        }
        #endregion 
            
    }
}
